/**
 * 修订记录：
 * No		日期						作者(操作内容)
 * 1.		2024年4月19日				805786(初始创建)	
 */
package com.lamect.job.service;

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import lombok.extern.slf4j.Slf4j;
import tech.powerjob.client.PowerJobClient;
import tech.powerjob.common.enums.DispatchStrategy;
import tech.powerjob.common.enums.ExecuteType;
import tech.powerjob.common.enums.ProcessorType;
import tech.powerjob.common.enums.TimeExpressionType;
import tech.powerjob.common.request.http.SaveJobInfoRequest;
import tech.powerjob.common.response.JobInfoDTO;
import tech.powerjob.common.response.ResultDTO;
import tech.powerjob.worker.core.processor.sdk.BasicProcessor;

/**
 * @ClassName：JobService
 * @Description：TODO
 * @Author：805786
 * @Date：2024年5月21日下午1:46:47
 */
@Slf4j
@Component
public class JobService {

	private final SimpleDateFormat SDF = new SimpleDateFormat("ss mm HH dd MM ?");
	
	@Resource
	private PowerJobClient powerJobClient;
	
	/**
	 * 设置基础参数
	 * @param jobName     任务名称
	 * @param jobParams   任务参数
	 * @param clazz	      处理器class
	 */
	public SaveJobInfoRequest setBaseParams(String jobName, String jobParams, Class<? extends BasicProcessor> clazz) {
		SaveJobInfoRequest request = new SaveJobInfoRequest();
    	// 任务名称
        request.setJobName(jobName);
        // 任务描述
        request.setJobDescription(jobName);
        // 任务参数，`TaskContext`对象的`jobParams`属性
    	request.setJobParams(jobParams);
    	// 执行类型，枚举值
    	request.setExecuteType(ExecuteType.STANDALONE);
    	// 处理器类型，枚举值
    	request.setProcessorType(ProcessorType.BUILT_IN);
    	// 处理器参数，填写类型由`processorType`决定，如Java处理器需要填写全限定类名
    	request.setProcessorInfo(clazz.getCanonicalName());
    	// 最大实例数，该任务同时执行的数量（任务和实例就像是类和对象的关系，任务被调度执行后被称为实例）
    	request.setMaxInstanceNum(1);
        // 单机线程并发数，表示该实例执行过程中每个Worker使用的线程数量
        request.setConcurrency(1);
        // 任务实例运行时间限制，0代表无任何限制，超时会被打断并判定为执行失败
        request.setInstanceTimeLimit(0l);
        // 任务实例重试次数，整个任务失败时重试，代价大，不推荐使用
        request.setInstanceRetryNum(0);
        // Task重试次数，每个子Task失败后单独重试，代价小，推荐使用
        request.setTaskRetryNum(0);
        // 最小可用CPU核心数，CPU可用核心数小于该值的Worker将不会执行该任务，0代表无任何限制
        request.setMinCpuCores(0);
        // 最小内存大小（GB），可用内存小于该值的Worker将不会执行该任务，0代表无任何限制
        request.setMinMemorySpace(0);
        // 最小磁盘大小（GB），可用磁盘空间小于该值的Worker将不会执行该任务，0代表无任何限制
        request.setMinDiskSpace(0);
        // 指定机器执行，设置该参数后只有列表中的机器允许执行该任务，空代表不指定机器
        request.setDesignatedWorkers(null);
        // 最大执行机器数量，限定调动执行的机器数量，0代表无限制
        request.setMaxWorkerCount(1);
        // 接收报警的用户ID列表
        request.setNotifyUserIds(CollUtil.newArrayList());
        // 是否启用该任务，未启用的任务不会被调度
        request.setEnable(true);
        // 调度策略，枚举，目前支持随机（RAMDOM）和健康度优先（HEALTH_FIRST）
        request.setDispatchStrategy(DispatchStrategy.HEALTH_FIRST);
        // 生命周期（预留，用于指定定时调度任务的生效时间范围）
        request.setLifeCycle(null);
        // 扩展字段（供开发者使用，用于功能扩展）
        request.setExtra(null);
        return request;
	}
	
	/**
	 * 创建固定频率任务
	 * @param jobName     任务名称
	 * @param jobParams   任务参数
	 * @param fixedRate   固定频率
	 * @param clazz	      处理器class
	 */
	public ResultDTO<Long> createFixedRate(String jobName, String jobParams, Long fixedRate, Class<? extends BasicProcessor> clazz) {
    	SaveJobInfoRequest request = setBaseParams(jobName, jobParams, clazz);
    	// 时间表达式类型，枚举值
    	request.setTimeExpressionType(TimeExpressionType.FIXED_RATE);
    	// 时间表达式，填写类型由`timeExpressionType`决定
    	request.setTimeExpression(Convert.toStr(fixedRate));
        ResultDTO<Long> result = powerJobClient.saveJob(request);
        log.info(">>> PowerJob createFixedRate {}，ID = {}", (result.isSuccess() ? "success" : "fail"), result.getData());
        if (!result.isSuccess()) log.error(">>> {}", result.getMessage());
        return result;
	}
	
	/**
	 * 创建定时任务
	 * @param jobName     任务名称
	 * @param jobParams   任务参数
	 * @param triggerCron 触发Cron
	 * @param clazz	      处理器class
	 */
	public ResultDTO<Long> create(String jobName, String jobParams, String triggerCron, Class<? extends BasicProcessor> clazz) {
		SaveJobInfoRequest request = setBaseParams(jobName, jobParams, clazz);
    	// 时间表达式类型，枚举值
    	request.setTimeExpressionType(TimeExpressionType.CRON);
    	// 时间表达式，填写类型由`timeExpressionType`决定
    	request.setTimeExpression(triggerCron);
        ResultDTO<Long> result = powerJobClient.saveJob(request);
        log.info(">>> PowerJob create {}，ID = {}", (result.isSuccess() ? "success" : "fail"), result.getData());
        if (!result.isSuccess()) log.error(">>> {}", result.getMessage());
        return result;
	}
	
	/**
	 * 创建定时任务
	 * @param jobName     任务名称
	 * @param jobParams   任务参数
	 * @param triggerDate 触发Date
	 * @param clazz	      处理器class
	 */
	public ResultDTO<Long> create(String jobName, String jobParams, Date triggerDate, Class<? extends BasicProcessor> clazz) {
        return create(jobName, jobParams, SDF.format(triggerDate), clazz);
	}
	
	/**
	 * 修改定时任务
	 * @param jobId       任务ID
	 * @param jobName     任务名称
	 * @param jobParams   任务参数
	 * @param triggerCron 触发Cron
	 * @param clazz	      处理器class
	 */
	public ResultDTO<Long> update(Long jobId, String jobName, String jobParams, String triggerCron, Class<? extends BasicProcessor> clazz) {
		SaveJobInfoRequest request = setBaseParams(jobName, jobParams, clazz);
    	// 任务ID，可选，null代表创建任务，否则填写需要修改的任务ID
    	request.setId(jobId);
    	// 时间表达式类型，枚举值
    	request.setTimeExpressionType(TimeExpressionType.CRON);
    	// 时间表达式，填写类型由`timeExpressionType`决定
    	request.setTimeExpression(triggerCron);
        ResultDTO<Long> result = powerJobClient.saveJob(request);
        log.info(">>> PowerJob update {}，ID = {}", (result.isSuccess() ? "success" : "fail"), result.getData());
        if (!result.isSuccess()) log.error(">>> {}", result.getMessage());
        return result;
	}
	
	/**
	 * 修改定时任务
	 * @param jobId       任务ID
	 * @param jobName     任务名称
	 * @param jobParams   任务参数
	 * @param triggerDate 触发Date
	 * @param clazz	      处理器class
	 */
	public ResultDTO<Long> update(Long jobId, String jobName, String jobParams, Date triggerDate, Class<? extends BasicProcessor> clazz) {
        return update(jobId, jobName, jobParams, SDF.format(triggerDate), clazz);
	}
	
	/**
	 * 删除定时任务
	 * @param jobId 任务ID
	 */
	public ResultDTO<Void> delete(Long jobId) {
		ResultDTO<Void> result = powerJobClient.deleteJob(jobId);
		log.info(">>> PowerJob delete {}，ID = {}", (result.isSuccess() ? "success" : "fail"), jobId);
        if (!result.isSuccess()) log.error(">>> {}", result.getMessage());
		return result;
	}
	
	/**
	 * 查找定时任务
	 * @param jobId 任务ID
	 */
	public ResultDTO<JobInfoDTO> fetchJob(Long jobId) {
		return powerJobClient.fetchJob(jobId);
	}
	
}
